package multi_thread.advanced;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Cheng Jun
 * Description: Atomic 保证是共享变量的原子性。
 * 下面的解释，针对51cto的视频课中的错误讲解，可以不用看。
 * https://edu.51cto.com/center/course/lesson/index?id=216061 视频中，老师的讲解有误。
 * 老师 举例说明 Atomic变量不能保证 方法的原子性，其实是不能保证方法的同步机制（隔离性），原子性指的是要么都执行，要么都不执行。
 * 如果一个程序执行一个操作 比如你去银行柜台存钱，要么存上了，要么存不上。也就是要么执行了，要么没执行。这就是原子性
 * 对于多个操作，比如 修改两条数据，你转账给别人，扣减你的账户余额和增加别人的账户余额 要保证 都执行或都不执行。这就是原子性。
 * 所以单个操作一般不说原子性，因为本身就是原子性的。
 * 还有 CAS的原子性操作的讲解是错误的，CAS没有使用版本号的概念，只是自旋校验而已。
 * <p>
 * @version 1.0
 * @date 2020/3/3 20:15
 */
public class AtomicExample {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.submit(new AtomicTest());
        }
        executorService.shutdown();
    }
}


class AtomicTest implements Runnable {

    // 注意: sum 一定要是类变量才能说明——多线程并发读/写操作是线程安全的。
    private static AtomicInteger sum = new AtomicInteger(0);

    @Override
    public void run() {
        // sum.toString() ==> return Integer.toString(get());
        // System.out.println(Thread.currentThread().getName() + "初始sum = " + sum);
        for (int i = 0; i < 10; i++) {
            sum.addAndGet(i);
        }
        System.out.println(Thread.currentThread().getName() + "计算后sum = " + sum.get());
        if (sum.get() == 450) {
            System.out.println("最终 sum = 450");
        }
    }
}
